package model;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;

import model.contents.Content;
import util.IModel;
import util.IView;
import util.LoggingUtils;
import util.PlayerUtilities;

public class Container implements IModel,Comparable<Container>{
	private int			id;
	private int			pageID;

	private String		name;

	private int			left;
	private int			top;
	private int			width;
	private int			height;
	private int			depth;
	// the views listening to this model
	private List<IView>	views;

	// the current playlist record being played on in the container
	private Content		content;
	private int			transition;
	
	private String	transitionType;

	public Container(int id, int pageID, String name, int left, int top, int width, int height, int depth) {
		this.id = id;
		this.pageID = pageID;
		this.name = (name == null || name.length() == 0) ? "Unnamed Container" : name;
		this.left = left;
		this.top = top;
		this.width = width;
		this.height = height;
		this.depth = depth;
		this.transition = -1;
		this.transitionType = "Normal";
		this.initializeOnLoad();
	}

	public static List<Container> getContainerListFromCSVFile(String fileName) {
		
		final String classMethod = "Container.java getContainerListFromCSVFile(String fileName)";
		LoggingUtils.logStart(classMethod);
		
		List<Container> containers = new ArrayList<Container>();
		if (!new File(fileName).exists()) {
			return containers;
		}
		List<String[]> csvData = PlayerUtilities.getArrayFromCSVFile(fileName);
		String[] fields = csvData.remove(0);
		// TODO: this is at a different abstraction level, 
		// TODO: we should extract this to make it the same level as the container obj
		for (String[] containerData : csvData) {
			int id = 0;
			int pageID = 0;
			String name = "";
			int left = 0;
			int top = 0;
			int width = 0;
			int height = 0;
			int depth = 0;
			boolean hasContainerID = false;
			boolean hasContainerName = false;

			// loop through each row and fetch container data
			for (int i = 0; i < fields.length; i++) {
				String field = fields[i];
				try {
					if (field.equals("container_id")) {
						hasContainerID = true;
						id = Integer.parseInt(containerData[i]);
					} else if (field.equals("page_id_fk")) {
						pageID = Integer.parseInt(containerData[i]);
					} else if (field.equals("name")) {
						hasContainerName = true;
						name = containerData[i];
					} else if (field.equals("left")) {
						left = Integer.parseInt(containerData[i]);
					} else if (field.equals("top")) {
						top = Integer.parseInt(containerData[i]);
					} else if (field.equals("width")) {
						width = Integer.parseInt(containerData[i]);
					} else if (field.equals("height")) {
						height = Integer.parseInt(containerData[i]);
					} else if (field.equals("z_index")) {
						depth = Integer.parseInt(containerData[i]);
					} else {
						System.err.println("invalid container field: " + field);
					}
				} catch (NumberFormatException ex) {
					System.out.println("invalid data format from source file.");
					LoggingUtils.log(Level.SEVERE, "Number format exception in " 
							+ classMethod,ex);
					ex.printStackTrace();
				}
				catch(ArrayIndexOutOfBoundsException ix)
				{
					LoggingUtils.log(Level.SEVERE, ix.getMessage() + classMethod,ix);
				}
				catch(NullPointerException nu)
				{
					LoggingUtils.log(Level.SEVERE, nu.getMessage() + classMethod,nu);
				}
			}
			
			if (hasContainerID && hasContainerName) {
				System.out.println(name);
				Container c = new Container(id, pageID, name, left, top, width, height, depth);
				containers.add(c);
			}
		}
		return containers;
	}

	/**
	 * @return the id
	 */
	public int getId() {
		return this.id;
	}

	/**
	 * @return the pageID
	 */
	public int getPageID() {
		return this.pageID;
	}

	/**
	 * @return the name
	 */
	public String getName() {
		return this.name;
	}

	/**
	 * @return the left
	 */
	public int getLeft() {
		return this.left;
	}

	/**
	 * @return the top
	 */
	public int getTop() {
		return this.top;
	}

	/**
	 * @return the width
	 */
	public int getWidth() {
		return this.width;
	}

	/**
	 * @return the height
	 */
	public int getHeight() {
		return this.height;
	}

	/**
	 * @return the depth
	 */
	public int getDepth() {
		return this.depth;
	}

	@Override
	public String toString() {
		return String.format("%s(%d): (%d,%d,%d,%d), depth: %d", this.getName(), this.getId(), this.getLeft(),
				this.getTop(), this.getWidth(), this.getHeight(), this.getDepth());
	}

	public Content getContent() {
		return this.content;
	}

	public void setContent(Content content) {
		this.content = content;
		synchronized (this.views) {
			for (IView view : this.views) {
				view.updateView(this, this.content);
			}
		}
	}

	@Override
	public void addView(IView view) {
		synchronized (this.views) {
			if (!this.views.contains(view)) {
				this.views.add(view);
			}
		}
	}

	@Override
	public void removeView(IView view) {
		synchronized (this.views) {
			if (this.views.contains(view)) {
				this.views.remove(view);
			}
		}
	}

	@Override
	public void removeAllViews() {
		synchronized (this.views) {
			if (this.views == null) {
				this.views = new ArrayList<IView>();
			}
			try
			{
				this.views.clear();
			}
			catch(Exception e)
			{
				System.out.println("Exception in clearing views from container.java removeallviews()");
				LoggingUtils.log(Level.SEVERE, e.getMessage(),e);
			}
		}
	}

	@Override
	public void notifyViews() {
		synchronized (this.views) {
			for (IView view : this.views) {
				view.updateView(this, null);
			}
		}
	}

	public void initializeOnLoad() {
		this.views = Collections.synchronizedList(new ArrayList<IView>());
	}
	
	@Override
	public int compareTo(Container con) {
		return this.getDepth() - con.getDepth();
	}

	// test for private members
	public static void main(String[] args) {
		boolean passed = true;
		Container c = new Container(1, 2, "S", 0, 50, 100, 200, 5);

		if (c.views.size() != 0) {
			System.out.println("number of views should be 0 when the container is initialized.");
			passed = false;
		}

		if (passed) {
			System.out.println("test passed.");
		}
	}

	public boolean isEmpty() {
		return this.content == null;
	}

	public void removeContent() {
		this.content = null;
	}

	@Override
	public int hashCode() {
		return this.id;
	}

	@Override
	public boolean equals(Object o) {
		if (o instanceof Container) {
			Container c = (Container) o;
			if (c.id == this.id) {
				return true;
			}
		}
		return false;
	}

	public void setTransition(int transition) {
		this.transition = transition;
	}

	public int getTransition() {
		return this.transition;
	}

	public String getTransitionType() {
		return transitionType;
	}

	public void setTransitionType(String transitionType) {
		this.transitionType = transitionType;
	}
	
}
